package com.feng.spring.hibernate.extend.proxy;

import com.feng.spring.hibernate.extend.HibernateExtendFactory;
import com.feng.spring.hibernate.extend.conf.HibernateExtendConfiguration;
import com.feng.spring.hibernate.extend.core.HibernateExtendSQLRegistry;
import com.feng.spring.hibernate.extend.core.sql.SQL;
import com.feng.spring.hibernate.extend.exception.HibernateExtendRuntimeException;
import org.apache.ibatis.annotations.Param;
import org.hibernate.SessionFactory;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class HibernateExtendInvocationHandler<T> implements InvocationHandler {

    private final Class<T> hibernateInterface;

    private HibernateExtendFactory hibernateExtendFactory;
    private HibernateExtendConfiguration hibernateExtendConfiguration;
    private HibernateExtendSQLRegistry registry;

    private SessionFactory sessionFactory;

    public HibernateExtendInvocationHandler(Class<T> hibernateInterface, HibernateExtendFactory hibernateExtendFactory) {
        this.hibernateInterface = hibernateInterface;
        this.hibernateExtendFactory = hibernateExtendFactory;
        this.hibernateExtendConfiguration = hibernateExtendFactory.getHibernateExtendConfiguration();
        this.registry = hibernateExtendConfiguration.getRegistry();
        this.sessionFactory = hibernateExtendFactory.getSessionFactory();
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        switch (method.getName()){
            case "equals":
                return (proxy == args[0]);
            case "hashCode":
                return System.identityHashCode(proxy);
            case "toString":
                StringBuilder sb = new StringBuilder("Hibernate-Extend proxy for ");
                sb.append('[').append(proxy.getClass()).append(']');
                return sb.toString();
        }

        List<SQL> sqlList = registry.get(hibernateInterface, method.getName());
        if (sqlList == null) {
            throw new HibernateExtendRuntimeException("未找到相关sql脚本！");
        }

        Map<String, Object> paramsKeyValue = new LinkedHashMap<>(args.length);
        Parameter[] parameters = method.getParameters();
        for (int i = 0; i < parameters.length; i++) {
            Parameter parameter = parameters[i];
            Param param = parameter.getAnnotation(Param.class);
            if (param != null){
                paramsKeyValue.put(param.value(), args[i]);
            }else {
                paramsKeyValue.put(parameter.getName(), args[i]);
            }
        }

        hibernateExtendFactory.getHibernateExtendSQLExecutor().decorate(paramsKeyValue);

        List<Object> queryParams = new ArrayList<>();
        String sql = hibernateExtendFactory.getHibernateExtendSQLBuilder().buildSQL(sqlList, paramsKeyValue, queryParams);

        return hibernateExtendFactory.getHibernateExtendSQLExecutor().execute(method, sessionFactory, sql, queryParams);
    }

}
